@@ -31,10 +31,10 @@ def member(request):  | 
            ||
| 31 | 31 | 
                     rights = RightInfo.objects.filter(status=True).order_by('position')
               | 
            
| 32 | 32 | 
                rights = [right.data for right in rights]  | 
            
| 33 | 33 | 
                 | 
            
| 34 | 
                -    goods = GoodsInfo.objects.filter(only_for_member=False, status=True).order_by('position')
               | 
            |
| 34 | 
                +    goods = GoodsInfo.objects.filter(only_for_member=False, left_num__gt=0, status=True).order_by('position')
               | 
            |
| 35 | 35 | 
                goods = [good.data(user_id) for good in goods][:2]  | 
            
| 36 | 36 | 
                 | 
            
| 37 | 
                -    member_goods = GoodsInfo.objects.filter(only_for_member=True, minlevel__lte=user.level, status=True).order_by('position')
               | 
            |
| 37 | 
                +    member_goods = GoodsInfo.objects.filter(only_for_member=True, left_num__gt=0, minlevel__lte=user.level, status=True).order_by('position')
               | 
            |
| 38 | 38 | 
                member_goods = [good.data(user_id) for good in member_goods]  | 
            
| 39 | 39 | 
                member_goods = [good for good in member_goods if not good['has_member_exchange']]  | 
            
| 40 | 40 | 
                 | 
            
                @@ -106,7 +106,7 @@ def goods(request):  | 
            ||
| 106 | 106 | 
                except UserInfo.DoesNotExist:  | 
            
| 107 | 107 | 
                return response(UserStatusCode.USER_NOT_FOUND)  | 
            
| 108 | 108 | 
                 | 
            
| 109 | 
                -    raw_goods = GoodsInfo.objects.filter(only_for_member=False, status=True).order_by('position')
               | 
            |
| 109 | 
                +    raw_goods = GoodsInfo.objects.filter(only_for_member=False, left_num__gt=0, status=True).order_by('position')
               | 
            |
| 110 | 110 | 
                banners = goods = []  | 
            
| 111 | 111 | 
                for good in raw_goods:  | 
            
| 112 | 112 | 
                if good.is_slider:  | 
            
                @@ -173,7 +173,7 @@ def good_exchange(request):  | 
            ||
| 173 | 173 | 
                return response(UserStatusCode.USER_NOT_FOUND)  | 
            
| 174 | 174 | 
                 | 
            
| 175 | 175 | 
                try:  | 
            
| 176 | 
                - good = GoodsInfo.objects.get(good_id=good_id)  | 
            |
| 176 | 
                + good = GoodsInfo.objects.select_for_update().get(good_id=good_id)  | 
            |
| 177 | 177 | 
                except GoodsInfo.DoesNotExist:  | 
            
| 178 | 178 | 
                return response(MemberGoodStatusCode.GOOD_NOT_FOUND)  | 
            
| 179 | 179 | 
                 | 
            
                @@ -186,6 +186,9 @@ def good_exchange(request):  | 
            ||
| 186 | 186 | 
                user.integral -= good.integral  | 
            
| 187 | 187 | 
                user.save()  | 
            
| 188 | 188 | 
                 | 
            
| 189 | 
                + good.left_num -= 1  | 
            |
| 190 | 
                + good.save()  | 
            |
| 191 | 
                +  | 
            |
| 189 | 192 | 
                GoodsOrderInfo.objects.create(  | 
            
| 190 | 193 | 
                user_id=user_id,  | 
            
| 191 | 194 | 
                good_id=good_id,  | 
            
                @@ -0,0 +1,25 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +# Generated by Django 1.11.26 on 2019-12-21 12:58  | 
            |
| 3 | 
                +from __future__ import unicode_literals  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +from django.db import migrations, models  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +class Migration(migrations.Migration):  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                + dependencies = [  | 
            |
| 11 | 
                +        ('member', '0014_auto_20191221_1613'),
               | 
            |
| 12 | 
                + ]  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                + operations = [  | 
            |
| 15 | 
                + migrations.AlterField(  | 
            |
| 16 | 
                + model_name='goodsinfo',  | 
            |
| 17 | 
                + name='left_num',  | 
            |
| 18 | 
                + field=models.IntegerField(db_index=True, default=0, help_text='\u5546\u54c1\u5e93\u5b58', verbose_name='left_num'),  | 
            |
| 19 | 
                + ),  | 
            |
| 20 | 
                + migrations.AlterField(  | 
            |
| 21 | 
                + model_name='goodsinfo',  | 
            |
| 22 | 
                + name='minlevel',  | 
            |
| 23 | 
                + field=models.IntegerField(db_index=True, default=0, help_text='\u5151\u6362\u6700\u4f4e\u4f1a\u5458\u7ea7\u522b', verbose_name='minlevel'),  | 
            |
| 24 | 
                + ),  | 
            |
| 25 | 
                + ]  | 
            
                @@ -28,7 +28,7 @@ class GoodsInfo(BaseModelMixin):  | 
            ||
| 28 | 28 | 
                title = models.CharField(_(u'title'), max_length=255, blank=True, null=True, help_text=u'商品名称')  | 
            
| 29 | 29 | 
                desc = RichTextField(_(u'desc'), blank=True, null=True, help_text=u'商品描述')  | 
            
| 30 | 30 | 
                value = models.IntegerField(_(u'value'), default=99999, help_text=u'商品价值,单位分')  | 
            
| 31 | 
                - left_num = models.IntegerField(_(u'left_num'), default=0, help_text=u'商品库存')  | 
            |
| 31 | 
                + left_num = models.IntegerField(_(u'left_num'), default=0, help_text=u'商品库存', db_index=True)  | 
            |
| 32 | 32 | 
                 | 
            
| 33 | 33 | 
                image = models.ImageField(_(u'image'), upload_to=upload_path, blank=True, null=True, help_text=u'商品图片')  | 
            
| 34 | 34 | 
                 | 
            
                @@ -40,7 +40,7 @@ class GoodsInfo(BaseModelMixin):  | 
            ||
| 40 | 40 | 
                integral = models.IntegerField(_(u'integral'), default=99999, help_text=u'兑换所需积分')  | 
            
| 41 | 41 | 
                fee = models.IntegerField(_(u'fee'), default=99999, help_text=u'兑换需额外支付金额,单位分')  | 
            
| 42 | 42 | 
                 | 
            
| 43 | 
                - minlevel = models.IntegerField(_(u'minlevel'), default=0, help_text=u'兑换最低会员级别')  | 
            |
| 43 | 
                + minlevel = models.IntegerField(_(u'minlevel'), default=0, help_text=u'兑换最低会员级别', db_index=True)  | 
            |
| 44 | 44 | 
                 | 
            
| 45 | 45 | 
                only_for_member = models.BooleanField(_(u'only_for_member'), default=False, help_text=u'会员专属', db_index=True)  | 
            
| 46 | 46 | 
                 |